{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "01cdbb56-dd0f-4ad7-ade0-5bd8e49ba4f8",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[NbConvertApp] Converting notebook feature_engineering.ipynb to script\n",
      "[NbConvertApp] Writing 3392 bytes to feature_engineering.py\n"
     ]
    },
    {
     "ename": "ImportError",
     "evalue": "cannot import name 'preprocess_data' from partially initialized module 'feature_engineering' (most likely due to a circular import) (D:\\jupyter notebook\\梧桐杯\\初赛项目\\code\\feature_engineering.py)",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mImportError\u001b[0m                               Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[2], line 11\u001b[0m\n\u001b[0;32m      8\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01msklearn\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mmetrics\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m accuracy_score, classification_report\n\u001b[0;32m     10\u001b[0m \u001b[38;5;66;03m# 从 feature_engineering 模块导入预处理函数\u001b[39;00m\n\u001b[1;32m---> 11\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mfeature_engineering\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m preprocess_data\n",
      "File \u001b[1;32mD:\\jupyter notebook\\梧桐杯\\初赛项目\\code\\feature_engineering.py:23\u001b[0m\n\u001b[0;32m     16\u001b[0m # 从 feature_engineering 模块导入预处理函数\n\u001b[0;32m     17\u001b[0m from feature_engineering import preprocess_data\n\u001b[0;32m     20\u001b[0m # In[ ]:\n\u001b[0;32m     21\u001b[0m \n\u001b[0;32m     22\u001b[0m \n\u001b[1;32m---> 23\u001b[0m #平均值特征构造\n\u001b[0;32m     24\u001b[0m def add_average_features(df):\n\u001b[0;32m     25\u001b[0m     columns_to_average = [\n\u001b[0;32m     26\u001b[0m         ('m1_owe_fee', 'm2_owe_fee', 'm3_owe_fee', 'mean_owe_fee'),  # 用户三个月的缴费\n\u001b[0;32m     27\u001b[0m         ('m1_calling_cnt', 'm2_calling_cnt', 'm3_calling_cnt', 'mean_calling_cnt'),  # 用户三个月的主叫次数\n\u001b[0;32m     28\u001b[0m         ('m1_comm_days', 'm2_comm_days', 'm3_comm_days', 'mean_comm_days'),  # 用户三个月通信天数\n\u001b[0;32m     29\u001b[0m         ('m1_hot_app_flow', 'm2_hot_app_flow', 'm3_hot_app_flow', 'mean_hot_app_flow')  # 用户三个月的热门APP使用流量\n\u001b[0;32m     30\u001b[0m     ]\n",
      "\u001b[1;31mImportError\u001b[0m: cannot import name 'preprocess_data' from partially initialized module 'feature_engineering' (most likely due to a circular import) (D:\\jupyter notebook\\梧桐杯\\初赛项目\\code\\feature_engineering.py)"
     ]
    }
   ],
   "source": [
    "import os\n",
    "import sys\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "import lightgbm as lgb\n",
    "import pickle\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.metrics import accuracy_score, classification_report\n",
    "\n",
    "# 从 feature_engineering 模块导入预处理函数\n",
    "from feature_engineering import preprocess_data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "63bc8f2a-a773-4085-bfca-a3403e30ce40",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 欠采样函数\n",
    "def undersample_data(X_data, sample_size=300000, base_random_state=2024):\n",
    "    features = X_data.drop('label', axis=1).columns\n",
    "    \n",
    "    # 获取正负样本\n",
    "    X_data1 = X_data[X_data['label'] == 1]\n",
    "    X_data2 = X_data[X_data['label'] == 0]\n",
    "\n",
    "    # 打乱负样本数据并重置索引\n",
    "    X_data2 = X_data2.sample(frac=1, random_state=base_random_state).reset_index(drop=True)\n",
    "\n",
    "    # 合并正负样本数据，并再次打乱顺序\n",
    "    X_data3 = pd.concat([X_data1, X_data2[:sample_size]], ignore_index=True)\n",
    "    X_data3 = X_data3.sample(frac=1, random_state=base_random_state).reset_index(drop=True)\n",
    "\n",
    "    # 分离特征和标签\n",
    "    X_data_sample = X_data3[features]\n",
    "    Y_data_sample = X_data3['label']\n",
    "    \n",
    "    return X_data_sample, Y_data_sample"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3ffd5b31-703b-4536-afe9-9f15aa9bf67e",
   "metadata": {},
   "outputs": [],
   "source": [
    "# LGB模型建立\n",
    "def build_model_lgb(x_train, y_train, eval_set=None, early_stopping_rounds=None):\n",
    "    model = lgb.LGBMClassifier(\n",
    "        num_leaves=128,\n",
    "        n_estimators=2000,\n",
    "        learning_rate=0.1,\n",
    "        metric='auc',\n",
    "        n_jobs=-1,\n",
    "        verbose=-1\n",
    "    )\n",
    "    model.fit(\n",
    "        x_train, y_train,\n",
    "        eval_set=[eval_set] if eval_set is not None else None,\n",
    "        early_stopping_rounds=early_stopping_rounds,\n",
    "        verbose=10  # 每10轮输出一次\n",
    "    )\n",
    "    return model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bf5d437b-012e-4256-acfb-53da9f7be995",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 基于LGB的集成模型构建\n",
    "def train_and_save_models(X_data, epochs=10, sample_size=300000, base_random_state=2024):\n",
    "    # 分割数据集\n",
    "    features = X_data.drop('label', axis=1).columns\n",
    "    X_train, X_val, y_train, y_val = train_test_split(X_data[features], X_data['label'], test_size=0.1, random_state=2024)\n",
    "    \n",
    "    for i in range(epochs):\n",
    "        # 欠采样\n",
    "        X_data_sample, Y_data_sample = undersample_data(X_data, sample_size, base_random_state)\n",
    "        print('Building and training LightGBM model...')\n",
    "        print(X_data_sample.shape, Y_data_sample.shape, X_val.shape, y_val.shape)\n",
    "        # 构建并训练模型\n",
    "        model_lgb = build_model_lgb(X_data_sample, Y_data_sample, eval_set=(X_val, y_val), early_stopping_rounds=50)\n",
    "\n",
    "        # 输出检测报告\n",
    "        print('Predicting on validation set...')\n",
    "        predictions = model_lgb.predict(X_val, num_iteration=model_lgb.best_iteration_)\n",
    "        print(classification_report(y_val, predictions))\n",
    "        # 保存模型\n",
    "        with open(f'model/model_lgb_{i}.pkl', 'wb') as f:\n",
    "            pickle.dump(model_lgb, f)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8a426553-b690-41ff-826a-ba51c549e667",
   "metadata": {},
   "outputs": [],
   "source": [
    "if __name__ == \"__main__\":\n",
    "    # 定义数据文件路径\n",
    "    train_path = '../init_data/raw/测试集A/train.csv'\n",
    "    # 预处理数据\n",
    "    train_data = preprocess_data(train_path)\n",
    "    train_data = train_data.drop('user_id', axis=1)\n",
    "    # 模型训练与保存\n",
    "    train_and_save_models(train_data)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
